#ifndef xpack_net_tcp
#define xpack_net_tcp
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::net_tcp::inc
#include"define/base_type.hpp"
#include"lang/cxx.hpp"
#include"macro/xhand_over.hpp"
#include"macro/xstruct.hpp"
#include"net/private/base_net.hpp"

#undef  xuser
#define xuser mixc::net_tcp::origin::tcp
#include"net/private/define.hpp"
#pragma pop_macro("xuser")

namespace mixc::net_tcp::inc{
    using namespace mixc::net_tcp::origin::tcp;

    extern ip_port_pair_v4 get_this_ip_port_pair_v4(ixx fd);
    extern ip_port_pair_v4 get_peer_ip_port_pair_v4(ixx fd);

    xstruct(
        xname(client_v4_base),
        xpubb(inc::base_net)
    )
        using inc::base_net::base_net;
        using inc::base_net::close;
        using inc::base_net::close_forcedly;

        client_v4_base()                        = default;
        client_v4_base(client_v4_base &&)       = default;
        xhand_over_with_close();

        bstate_t open(reuse_address_t mode = reuse_address_t::system_default) const;

        bstate_t open_with_bind(ipv4 ip, u16 port, reuse_address_t mode = reuse_address_t::system_default) const;

        bstate_t bind(ipv4 ip, u16 port) const;

        bstate_t connect(ipv4 ip, u16 port) const;

        uxx read(voidp buffer, uxx bytes) const;

        uxx read_non_block(voidp buffer, uxx bytes) const;

        uxx write(inc::c08 const & value) const {
            return this->write(asciis(value), value->length);
        }

        uxx write_non_block(inc::c08 const & value) const {
            return this->write_non_block(asciis(value), value->length);
        }

        uxx write(void const * buffer, uxx bytes) const;

        uxx write_non_block(void const * buffer, uxx bytes) const;

        friend struct service_v4;
    $
}

namespace mixc::net_tcp::origin::tcp{
    xstruct(
        xname(client_v4),
        xpubb(inc::client_v4_base)
    )
        xprops()
            xpubgetx(ip_port_pair, ip_port_pair_v4){
                xr{ return inc::get_this_ip_port_pair_v4(xthe.m_fd); }
            };
        $

        xprops_operator()
    $

    xstruct(
        xname(client_item_v4),
        xpubb(inc::client_v4_base)
    )
        client_item_v4()                        = default;
        client_item_v4(client_item_v4 &&)       = default;
        xhand_over_with_close();

        xprops()
            xpubgetx(ip_port_pair, ip_port_pair_v4){
                xr{ return inc::get_peer_ip_port_pair_v4(xthe.m_fd); }
            };
        $

        xprops_operator()

        using inc::client_v4_base::client_v4_base;
    private:
        using inc::client_v4_base::open;
        using inc::client_v4_base::open_with_bind;
        using inc::client_v4_base::connect;

        friend struct service_v4;
        friend struct client_v4;
    $

    xstruct(
        xname(service_v4),
        xpubb(inc::base_net)
    )
        service_v4()                    = default;
        service_v4(service_v4 &&)       = default;
        xhand_over_with_close();

        using inc::base_net::base_net;

        bstate_t open(reuse_address_t mode = reuse_address_t::system_default) const;

        bstate_t bind(ipv4 ip, u16 port) const;

        bstate_t open_with_bind(ipv4 ip, u16 port, reuse_address_t mode = reuse_address_t::system_default) const;

        bstate_t listen(uxx max_link) const;

        client_item_v4 accept() const;
    $

    using inc::sock_type_t;
}

#endif

xexport_space(mixc::net_tcp::origin)
